﻿using System;
using System.Collections.Generic;
using System.Text;
using System.IO;
using System.Net;
using PushEmail.Mime;
using PushEmail.Common;
using PushEmail.Common.Logging;
using PushEmail.Global;

namespace MyMailWp8.Protocol
{
    public delegate Account CallBackGetSmtpAccountInfo();

    public class CMSmtp
    {
        public event TransportEventHandler TransportEvent;

        private CMSmtpState _nPopState;
        private CMPopBase _cmPopCommand;
        private AsyncSocketClient _sockClient;
        private List<Email> sendMailList;
        private SentMailNotify sentNotify;
        

        private int totalcount = 0;
        private int sentCount = 0;
        private System.Object lockObject = new System.Object();
       
        public CMSmtp(SentMailNotify notify, TransportEventHandler TransportEvent) 
        {
            sentNotify = notify;
            
            sentCount = 0;
            //uint folderId = PEDBManager.Instance().peDataModel.GetSystemFolderIdByType(accountId,FolderType.outBoxType);
            //sendMailList = PEDBManager.Instance().peDataModel.GetMailsByFolderId(accountId, folderId);
            List<Email> sendMailList = PEDBManager.Instance().peDataModel.GetMailsByFolderType(FolderType.outBoxType);
            if (TransportEvent != null)
                this.TransportEvent += TransportEvent;
            if ((sendMailList == null) || (sendMailList.Count == 0))
                throw new Exception("no mail in outbox");
            totalcount = sendMailList.Count;


            _nPopState = CMSmtpState.CMSmtp_Init;
            Account account = PEDBManager.Instance().peDataModel.Get139Account();
            if (account != null)
            {
                _sockClient = new AsyncSocketClient(account.outServer, Convert.ToInt32(account.outPort));//MIG
            }
            else
            {
                DefaultLogger.Log.LogDebug("can't get account info");
                throw (new Exception("not found mail server"));
            }

            //_sockClient = new AsyncSocketClient("123.58.177.137", 143);            
            _sockClient.ResponseReceived += new ResponseReceivedHandler(CMSmtpCallBack);
        }

         public void StartCMSmtpSend()
        {
            if (_nPopState != CMSmtpState.CMSmtp_Init) 
                return;
            try
            {
                _sockClient.connectToSever();
            }
            catch (PESocketException ex)
            {
                callErrorTransportEvent(ex.Message, ex.ErrCode);
            }
        }
       
        public void StopCMSmtpSend()
        {
            if (_nPopState != CMSmtpState.CMSmtp_Quit) 
                return;

            _nPopState = CMSmtpState.CMSmtp_Init;
            _sockClient.disConnectToSever();

            _cmPopCommand = null;
            DefaultLogger.Log.LogDebug("StopCMPopRecv" + "\r\n");
        }

        public void Dispose()
        {
            lock (lockObject)
            {
                try
                {
                    TransportEvent = null;
                    sentNotify = null;
                    CMSmtpChangeState((int)CMPopState.CMPOP_Quit);
                    _sockClient.disConnectToSever();
                }
                catch (Exception e)
                {
                    DefaultLogger.Log.LogDebug("Dispose CMSmtp " + e.ToString());
                }
            }
        }


        void CMSmtpChangeState(int nState)
        {
            _nPopState = (CMSmtpState)nState;

            switch (_nPopState)
            {
                case CMSmtpState.CMSmtp_Init:
                    break;

                case CMSmtpState.CMSmtp_Login:
                    _cmPopCommand = null;       
                    {
                        _cmPopCommand = new CMSmtpLogin(_sockClient);
                        _cmPopCommand.CMPopSmtpStateChanged += new CMPopStateEventHandler(CMSmtpChangeState);
                        _cmPopCommand.TransportEvent += this.TransportEvent;
                    }
                    _cmPopCommand.ReceiveData();
                    break;

                case CMSmtpState.CMSmtp_Send:
                    _cmPopCommand = null;                    
                    {
                        _cmPopCommand = new CMSmtpSend(_sockClient, sendMailList);
                        _cmPopCommand.CMPopSmtpStateChanged += new CMPopStateEventHandler(CMSmtpChangeState);
                        _cmPopCommand.TransportEvent += this.TransportEvent;
                        ((CMSmtpSend)_cmPopCommand).sendOneMail();

                        //_cmPopCommand.SendData("MAIL FROM:<" + sendMail.fromAddress + ">" + "\r\n");
                    }
                    break;

                case CMSmtpState.CMSmtp_SendDATA:
                    {
                        DefaultLogger.Log.LogDebug("mail sending and notify to UI" + "\r\n");
                    }
                    break;

                case CMSmtpState.CMSmtp_SendOneMail:
                    {
                        sentCount++;
                        //send notify to UI 
                        lock (lockObject)
                        {
                            if (sentNotify != null)
                            {
                                uint mailId = 0;
                                CMSmtpSend smtpSend = _cmPopCommand as CMSmtpSend;
                                if (smtpSend != null)
                                {
                                    mailId = smtpSend.sendMail.emailId;
                                }

                                System.Windows.Deployment.Current.Dispatcher.BeginInvoke(() =>
                                {
                                    sentNotify.SentMailNotify(totalcount, (int)mailId);
                                });
                            }
                        }
                        DefaultLogger.Log.LogDebug("SendOneMail and send notify to UI" + "\r\n");
                    }
                    break;

                case CMSmtpState.CMSmtp_Quit:
                    _cmPopCommand = null;
                    _cmPopCommand = new CMPopBase(_sockClient);
                    _cmPopCommand.TransportEvent += this.TransportEvent;
                    _cmPopCommand.SendData("QUIT\r\n");
                    DefaultLogger.Log.LogDebug("QUIT\r\n");
                    break;

                default:
                    break;
            }
        }

        void CMSmtpProcessConnectMessage()
        {
            switch (_nPopState)
            {
                case CMSmtpState.CMSmtp_Init:
                    CMSmtpChangeState((int)(CMSmtpState.CMSmtp_Login));
                    break;
                default:
                    break;
            }
        }

        void CMSmtpProcessSendMessage()
        {
            switch (_nPopState)
            {
                case CMSmtpState.CMSmtp_Init:
                    //do nothing
                    break;
                case CMSmtpState.CMSmtp_Login:
                    if (_cmPopCommand != null)
                        _cmPopCommand.ReceiveData();
                    break;

                case CMSmtpState.CMSmtp_Send:
                case CMSmtpState.CMSmtp_SendOneMail:
                    if (_cmPopCommand != null)
                        _cmPopCommand.ReceiveData();
                    break;

                case CMSmtpState.CMSmtp_SendDATA:
                case CMSmtpState.CMSmtp_SendEFWD:
                    if (_cmPopCommand != null)
                        _cmPopCommand.ProcessSendSucess();
                    break;

                case CMSmtpState.CMSmtp_Quit:
                    StopCMSmtpSend();
                    break;

                default:
                    break;
            }
        }

        void CMSmtpProcessReceiveMessage(string recvString)
        {
            switch (_nPopState)
            {
                case CMSmtpState.CMSmtp_Init:
                    //do nothing
                    break;
                case CMSmtpState.CMSmtp_Login:
                case CMSmtpState.CMSmtp_Send:
                case CMSmtpState.CMSmtp_SendDATA:
                case CMSmtpState.CMSmtp_SendOneMail:
                case CMSmtpState.CMSmtp_SendEFWD:
                    if (_cmPopCommand != null)
                        _cmPopCommand.ParseData(recvString);
                    break;
                default:
                    break;
            }
        }

        void CMSmtpCallBack(object sender, ResponseReceivedEventArgs e)
        {
            if (e.nMessageType == (int)SockMessageType.ConnectSucess)
            {
                CMSmtpProcessConnectMessage();
            }
            else if (e.nMessageType == (int)SockMessageType.SendSucess)
            {
                CMSmtpProcessSendMessage();
            }
            else if (e.nMessageType == (int)SockMessageType.ReceiveSucess)
            {
                CMSmtpProcessReceiveMessage(e.response);
            }
            else 
            {
                string strErr = "";
                switch (e.nMessageType)
                {
                    case (int)SockMessageType.ConnectFail:
                        strErr = PushEmail.Resource.Strings.ERR_NET_CONNECT;
                        break;
                    case (int)SockMessageType.ReceiveFail:
                        strErr = PushEmail.Resource.Strings.ERR_NET_RECEIVE;
                        break;
                    case (int)SockMessageType.SendFail:
                        strErr = PushEmail.Resource.Strings.ERR_NET_SEND;
                        break;
                    default:
                        break;

                }
                callErrorTransportEvent(strErr, e.nMessageType);
            }
        }

        public void callErrorTransportEvent(string strErr, int errCode)
        {
            try
            {
                lock (lockObject)
                {
                    if (_cmPopCommand != null)
                        _cmPopCommand.ProcessSendFailed();                   
                    if (TransportEvent != null)
                    {
                        TransportEvent(strErr, errCode);
                    }
                }
            }
            catch (Exception e)
            {
                DefaultLogger.Log.LogDebug("CMPopCallNotifyInterface Exception" + e.ToString());
            }
        }

    }
}

